<?PHP
/*
 * $Id: BeanUtilsTest.class.php 156 2009-12-16 15:59:00Z namba0219 $
 * =============================================================================
 * Barge - Web application framework on PHP5
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * =============================================================================
 * For more information, see http://barge.googlecode.com/
 */
namespace barge\utils;

use \Exception;
use \ReflectionException;
use \UnitTestCase;

use barge\utils\ArrayList;
use barge\utils\HashMap;
use barge\utils\BeanUtils;
use barge\utils\IndexOutOfBoundsException;
use barge\utils\IllegalAccessException;

/**
 * {@link BeanUtils}テストケース
 *
 * @author Kenji Namba
 * @see UnitTestCase
 */
class BeanUtilsTest extends UnitTestCase
{

	/**
	 * @test
	 */
	public function testGetPropertyDescriptors()
	{
		$model = new _SimpleBean(1, 'Bob');
		$descriptors = BeanUtils::getPropertyDescriptors($model);
		$this->assertIdentical($descriptors->size(), 8);
//		$this->assertIdentical($descriptors->get(0)->getName(), 'userId');
//		$this->assertIdentical($descriptors->get(0)->isReadable(), true);
//		$this->assertIdentical($descriptors->get(0)->isWritable(), false);
//		$this->assertIdentical($descriptors->get(0)->getReadMethod()->invoke($model), 1);
//		$this->assertIdentical($descriptors->get(1)->getName(), 'name');
//		$this->assertIdentical($descriptors->get(1)->isReadable(), true);
//		$this->assertIdentical($descriptors->get(1)->isWritable(), true);
//		$this->assertIdentical($descriptors->get(1)->getReadMethod()->invoke($model), 'Bob');
//		$this->assertIdentical($descriptors->get(2)->getName(), 'gender');
//		$this->assertIdentical($descriptors->get(2)->isReadable(), false);
//		$this->assertIdentical($descriptors->get(2)->isWritable(), true);
//		$this->assertIdentical($descriptors->get(3)->getName(), 'marriage');
//		$this->assertIdentical($descriptors->get(3)->isReadable(), true);
//		$this->assertIdentical($descriptors->get(3)->isWritable(), true);
	}

	/**
	 * @test
	 */
	public function testGetPropertyDescriptor()
	{
		$model = new _SimpleBean(1, 'Bob');
		$propertyDescriptor = BeanUtils::getPropertyDescriptor($model, 'name');
		$this->assertNotNull($propertyDescriptor);
		$this->assertIdentical($propertyDescriptor->isReadable(), true);
		$this->assertIdentical($propertyDescriptor->isWritable(), true);
		$this->assertIdentical($propertyDescriptor->getClassType(), null);
		$this->assertIdentical($propertyDescriptor->getName(), 'name');
		$this->assertIsA($propertyDescriptor->getReader(), 'barge\utils\AccessorPropertyReader');
		$this->assertIsA($propertyDescriptor->getWriter(), 'barge\utils\AccessorPropertyWriter');
		$propertyDescriptor = BeanUtils::getPropertyDescriptor($model, 'secret');
		$this->assertNotNull($propertyDescriptor);
		$this->assertIdentical($propertyDescriptor->isReadable(), true);
		$this->assertIdentical($propertyDescriptor->isWritable(), true);
		$this->assertIdentical($propertyDescriptor->getClassType(), null);
		$this->assertIsA($propertyDescriptor->getReader(), 'barge\utils\DirectPropertyReadWriter');
		$this->assertIsA($propertyDescriptor->getWriter(), 'barge\utils\DirectPropertyReadWriter');


		// TODO :
	}

	/**
	 * @test
	 */
	public function testGetProperty()
	{
		$model = new _SimpleBean(1, 'Bob');
		$this->assertIdentical(BeanUtils::getProperty($model, 'userId'), 1);
		$this->assertIdentical(BeanUtils::getProperty($model, 'name'), 'Bob');
		try {
			BeanUtils::getProperty($model, 'xxx');
			$this->fail();
		} catch (ReflectionException $e) {}

		// ネスト
		$model->getNested()->setName('john');
		$this->assertIdentical(BeanUtils::getProperty($model, 'nested.name'), 'john');
		// public プロパティー
		$this->assertIdentical(BeanUtils::getProperty($model, 'address'), 'New York');

		// アノテーション
		$this->assertIdentical(BeanUtils::getProperty($model, 'q'), 'keyword');

		// アノテーション+アクセッサー
		$this->assertIdentical(BeanUtils::getProperty($model, 'ln'), 'ja');

		// TODO :
		$model = new HashMap();
	}

	/**
	 * @test
	 */
	public function testSetProperty()
	{
		$model = new _SimpleBean(1, 'Bob');

		// プロパティーの指定
		BeanUtils::setProperty($model, 'name', 'John');
		$this->assertIdentical($model->getUserId(), 1);
		$this->assertIdentical($model->getName(), 'John');

		// 書き込みメソッドが存在しないプロパティーを指定
		try {
			BeanUtils::setProperty($model, 'userId', 2);
		} catch (ReflectionException $e) {}

		// アクセス不可能な書き込みメソッドを指定
		try {
			BeanUtils::setProperty($model, 'secret', 2);
		} catch (ReflectionException $e) {}

		// HashMap に対する設定
		$model = new HashMap();
		BeanUtils::setProperty($model, 'userId', 1);
		$this->assertIdentical($model->get('userId'), 1);
		BeanUtils::setProperty($model, 'name', 'John');
		$this->assertIdentical($model->get('name'), 'John');

		// ネスト
		$model = new _SimpleBean(1, 'Bob');
		BeanUtils::setProperty($model, 'nested.name', 'Robyn');
		$this->assertIdentical($model->getNested()->getName(), 'Robyn');

		// public プロパティー
		BeanUtils::setProperty($model, 'address', 'Japan');
		$this->assertIdentical($model->address, 'Japan');

		// アノテーション
		BeanUtils::setProperty($model, 'q', 'キーワード');
		$this->assertIdentical($model->query, 'キーワード');

		// アノテーション+アクセッサー
		BeanUtils::setProperty($model, 'ln', 'us');
		$this->assertIdentical($model->getLang(), 'us');
	}

	/**
	 * @test
	 */
	public function testCopyProperties()
	{
		$beanUtils = new BeanUtils();
		// TODO :
	}

	/**
	 * @test
	 */
	public function testToMap()
	{
		$model = new _SimpleBean(1, 'Jhone');
		$model->setGender(1);
		$map = BeanUtils::toMap($model);
		$this->assertTrue($map instanceof HashMap);
		$this->assertIdentical($map->get('userId'), 1);
		$this->assertIdentical($map->get('name'), 'Jhone');
		$this->assertIdentical($map->get('gender'), null);
		$this->assertIdentical($map->get('birthday'), null);
		// TODO :
//		$this->assertIdentical($map->get('q'), 'keyword');
		// TODO :
	}
}

// Model for test
class _SimpleBean
{
	/** static ダミー */
	public static $trap;

	/** プロパティー名とアクセッサー名が異なる */
	private $user_id;
	public function getUserId() { return $this->user_id; }

	/** protected */
	protected $name;
	public function getName() { return $this->name; }
	public function setName($value) { $this->name = $value; }

	/** アクセッサーなし  */
	private $birthday;

	/** アクセッサーがpublicでない  */
	public $secret = 1;
	protected function getSecret() { return $this->secret; }
	protected function setSecret($value) { $this->secret = $value; }

	/** public プロパティー */
	public $address = "New York";


	/** 読み込みメソッドなし */
	public $gender;
	public function setGender($value) { $this->gender = $value; }

	/** ネストしたモデル */
	public $nested;
	/** @return _NestedBean */
	public function getNested() { return $this->nested; }
	public function setNested($value) { $this->nested = $value; }

	/**
	 * アノテーション付きパブリックプロパティー
	 * @~barge\utils\Property(name="q")
	 */
	public $query = 'keyword';

	/**
	 * アノテーション付きアクセッサープロパティー
	 * @~barge\utils\Property(name="ln")
	 */
	private $lang = 'ja';
	public function getLang() { return $this->lang; }
	public function setLang($value) { $this->lang = $value; }

	public function __construct($id, $name)
	{
		$this->user_id = $id;
		$this->name = $name;
		$this->nested = new _NestedBean();
	}



}


// Model for test
class _NestedBean
{
	/** Model */
	private $name;

	// protected
	public function getName()
	{
		return $this->name;
	}

	public function setName($value)
	{
		$this->name = $value;
	}
}

